#include <iostream>
#include <cstring>
#include <cstdio>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/bio.h>

#define PUB_MOD_BITS		2048
#define PUB_EXP				RSA_F4
#define PADDING				RSA_PKCS1_OAEP_PADDING
#define CARRIER_PUB_KEY		"carrierPubKey.pem"
#define CARRIER_PRIV_KEY	"carrierPrivKey.pem"

using namespace std;

int main5() {
	// generate & check keys
	RSA* rsa = RSA_generate_key(PUB_MOD_BITS, PUB_EXP, NULL, 0);
	int check_key = RSA_check_key(rsa);
	while (check_key <= 0) {
		cerr << "error generating keys -- regenerating...";
		rsa = RSA_generate_key(PUB_MOD_BITS, PUB_EXP, NULL, 0);
		check_key = RSA_check_key(rsa);
	}
	RSA_blinding_on(rsa, NULL);

	// write out pem-encoded public key
	BIO* rsaPublicBio = BIO_new_file(CARRIER_PUB_KEY, "w");
	PEM_write_bio_RSA_PUBKEY(rsaPublicBio, rsa);

	// write out pem-encoded encrypted private key
	BIO* rsaPrivateBio = BIO_new_file(CARRIER_PRIV_KEY, "w");
	PEM_write_bio_RSAPrivateKey(rsaPrivateBio, rsa, NULL, NULL, 0, NULL, NULL);

	BIO_free(rsaPublicBio);
	BIO_free(rsaPrivateBio);
	RSA_free(rsa);

	// read in pem-encoded public key
	BIO* rsaPublicBio2 = BIO_new_file(CARRIER_PUB_KEY, "r");
	RSA* rsaPub = RSA_new();
	PEM_read_bio_RSA_PUBKEY(rsaPublicBio2, &rsaPub, NULL, NULL);
	BIO_free(rsaPublicBio2);

	// read in pem-encoded encrypted private key
	BIO* rsaPrivateBio2 = BIO_new_file(CARRIER_PRIV_KEY, "r");
	RSA* rsaPriv = RSA_new();
	PEM_read_bio_RSAPrivateKey(rsaPrivateBio2, &rsaPriv, NULL, NULL);
	BIO_free(rsaPrivateBio2);

	printf("Tell me a secret: ");
	int size = RSA_size(rsaPub);
	unsigned char secret[size];
	memset((void*) secret, 0, size);
	gets((char*) secret);

	unsigned char* encrypt_buf = new unsigned char[size];
	memset((void*) encrypt_buf, 0, size);
	int encrypt_size = RSA_public_encrypt(strlen((const char*) secret) + 1,
			secret, encrypt_buf, rsaPub, PADDING);

	cout << "secret:      " << secret << endl;
	cout << "encrypt_buf: " << encrypt_buf << endl;

	size = RSA_size(rsaPriv);
	unsigned char* decrypt_buf = new unsigned char[size];
	memset((void*) decrypt_buf, 0, size);
	RSA_private_decrypt(encrypt_size, encrypt_buf, decrypt_buf, rsaPriv,
			PADDING);

	cout << "decrypt_buf: " << decrypt_buf << endl;

	RSA_free(rsaPub);
	RSA_free(rsaPriv);
	delete encrypt_buf;
	delete decrypt_buf;

	return 0;
}
